#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <mswsock.h>
#include <ws2tcpip.h>

void error(const char *msg)
{
	DWORD err, res;
	char buf[500];

	err = WSAGetLastError();
	res = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,
		NULL, err, 0, buf, sizeof(buf), NULL);
	if (res > 0)
		fprintf(stderr, "err: %d '%s', %s\n", err, msg, buf);
	else
		err = GetLastError();
    exit(0);
}

int sockatmark(int s)
{
	int arg=99;
	if (ioctlsocket(s, SIOCATMARK, &arg) < 0)
		error("ioctlsocket");
	return arg;
}

int readloop(int s)
{
    char buf[100];
    int res, cnt;
    fd_set rfds, xfds;
    struct timeval tv;

    FD_ZERO(&rfds);
    FD_ZERO(&xfds);
    FD_SET(s, &rfds);
    FD_SET(s, &xfds);
    tv.tv_sec = 5;
    tv.tv_usec = 0;

    res = select(FD_SETSIZE, &rfds, NULL, &xfds, &tv);
    printf("select returned %d, rfd is %d, xfd is %d\n", res, FD_ISSET(s, &rfds), FD_ISSET(s, &xfds));
    res = sockatmark(s);
    printf ("sockatmark returned %d\n", res);
	if (res == 0)
	{
		int oobinline = 1;
		printf("setting oobinline to %d\n", oobinline);
		if (setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char*)&oobinline, sizeof(oobinline)) < 0)
			error("setsockopt oobinline");
	}
    cnt = recv(s, buf, sizeof(buf)-1, 0);
    if (cnt >= 0)
    {
		buf[cnt] = 0;
    	printf("recv returned '%s'\n", buf);
    }
    else
		error("recv");
//		printf("recv returned %d\n", cnt);
    res = sockatmark(s);
    printf ("sockatmark returned %d\n", res);
    return cnt;
}

int main(int argc, char *argv[])
{
    int s, s1, addrlen, cnt;
	int oobinline=0, bsdurgent=1;
    struct sockaddr_in addr, cliaddr;
//	struct timeval tv = {2, 0};
	int timeout = 4000, val = 0, valsize = sizeof(val);
	WSADATA wsadata;

	if (argc != 2)
	{
		printf("usage: testsrv <port>\n");
		return 1;
	}
	memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(atoi(argv[1]));
    addr.sin_addr.s_addr = INADDR_ANY;

	if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0)
		error("WSAStartup");
    s = socket(AF_INET, SOCK_STREAM, 0);
    if (s == INVALID_SOCKET)
		error("socket");
	if (setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout)) < 0)
		error("setsockopt 1");
	if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout)) < 0)
		error("setsockopt 2");
    if (bind(s, (struct sockaddr*)&addr, sizeof(addr)) < 0)
		error("bind");
    if (listen(s, 1) < 0)
		error("listen");
    addrlen = sizeof(cliaddr);
    s1 = accept(s, (struct sockaddr*)&cliaddr, &addrlen);
    if (s1 == INVALID_SOCKET)
		error("accept1");
	printf("foo 1\n");
	if (closesocket(s) < 0)
		error("close s");
	{
		struct sockaddr saddr = {0};
		int saddrlen = sizeof(saddr), i;

		if (getsockname(s1, &saddr, &saddrlen) < 0)
			error("getsockname");
		printf("getsockaddr: ");
		for (i=0; i<saddrlen; i++)
			printf("%02x ", (int)((char*)&saddr)[i]);
		printf("\n");
	}

	//s1 = accept(s, (struct sockaddr*)&cliaddr, &addrlen);
	//   if (s1 == INVALID_SOCKET)
		//	error("accept2");

	if (getsockopt(s1, SOL_SOCKET, SO_RCVTIMEO, (char*)&val, &valsize) < 0)
		error("getsockopt");
	printf("getsockopt RCVTIMEO on accepted socket is %d\n", val);
	printf("setting oobinline to %d\n", oobinline);
    if (setsockopt(s1, SOL_SOCKET, SO_OOBINLINE, (char*)&oobinline, sizeof(oobinline)) < 0)
		error("setsockopt oobinline");
	printf("foo 2\n");
//    if (setsockopt(s1, IPPROTO_TCP, TCP_NOURG, (char*)&bsdurgent, sizeof(bsdurgent)) < 0)
//		error("setsockopt bsdurgent");
	printf("foo 3\n");
    do
    {
		cnt = readloop(s1);
    } while (cnt);
    if (closesocket(s1) < 0)
		error("close s1");
	WSACleanup();
	return 0;
}

